#include "sbull_internal.h"

#include "user_copy.h"
#include "hdf_log.h"
#include "hdf_base.h"

// before read
static int32_t sbullPreRead(char *buffer, uint32_t bytes, char **newbuf)
{
    if (LOS_IsUserAddressRange((VADDR_T)buffer, bytes)) { // 是来自用户空间的请求
        *newbuf = LOS_MemAlloc(m_aucSysMem0, bytes); // 申请一个缓冲区
        if (*newbuf == NULL) {
            dprintf("[%s]fatal memory allocation error\n", __FUNCTION__);
            return -ENOMEM;
        }
    } else { // 内核空间的请求
        *newbuf = buffer; // 直接使用目的缓冲区
    }
    return 0;
}

// after read
static int32_t sbullPostRead(char *buffer, char *newbuf, uint32_t bytes, int32_t ret)
{
    if (newbuf != buffer) { // 来自用户空间的请求
        if (LOS_ArchCopyToUser(buffer, newbuf, bytes) != 0) {
            dprintf("[%s]LOS_ArchCopyToUser error\n", __FUNCTION__);
            ret = -EFAULT;
        }

        if (LOS_MemFree(m_aucSysMem0, newbuf) != 0) {
            dprintf("[%s]LOS_MemFree error\n", __FUNCTION__);
            ret = -EFAULT;
        }
    }
    return ret;
}

// before write
static int32_t sbullPreWrite(const char *buffer, uint32_t bytes, char **newbuf)
{
    if (LOS_IsUserAddressRange((VADDR_T)buffer, bytes)) { // 来自用户空间的请求
        *newbuf = LOS_MemAlloc(m_aucSysMem0, bytes);// 申请一个缓冲区
        if (*newbuf == NULL) {
            dprintf("[%s]fatal memory allocation error\n", __FUNCTION__);
            return -ENOMEM;
        }

        if (LOS_ArchCopyFromUser(*newbuf, buffer, bytes)) { // 拷贝到内核空间
            dprintf("[%s]LOS_ArchCopyFromUser error\n", __FUNCTION__);
            LOS_MemFree(m_aucSysMem0, *newbuf);
            return -EFAULT;
        }
    } else {
        *newbuf = (char*)buffer;
    }
    return 0;
}

// after write
static int32_t sbullPostWrite(const char *buffer, char *newbuf, int32_t ret)
{
    if (newbuf != buffer) { // 来自用户空间的请求
        if (LOS_MemFree(m_aucSysMem0, newbuf) != 0) {
            dprintf("[%s]LOS_MemFree error\n", __FUNCTION__);
            return -EFAULT;
        }
    }
    return ret;
}

///////////////////////////////////////////////////////////////
// 字符设备驱动
///////////////////////////////////////////////////////////////
int sbullCharOpen(struct file *filep)
{
    // int32_t ret;
    // struct Vnode *vnode = NULL;
    // struct drv_data *data = NULL;

    // mtd_partition *partition = NULL;
    // struct MtdDev *mtd = NULL;

    // UINT32 blockSize = 0;

    // if (filep == NULL || filep->f_vnode == NULL) {
    //     return HDF_ERR_INVALID_PARAM;
    // }

    // // vnode
    // vnode = (struct Vnode *)filep->f_vnode;
    // if (vnode->data == NULL) {
	// 	return HDF_ERR_INVALID_PARAM;
	// }

    // // drv_data
    // data = vnode->data;
	// if (data->priv == NULL) {
	// 	return HDF_ERR_INVALID_PARAM;
	// }

    // // partition / mtd
    // partition = (mtd_partition *)data->priv;
    // mtd = (struct MtdDev *)partition->mtd_info;

    // // block size
    // blockSize = mtd->eraseSize;

    // (void)LOS_MuxLock(&partition->lock, LOS_WAIT_FOREVER);

    // partition->user_num++;
    // filep->f_pos = partition->start_block * blockSize;

    // (void)LOS_MuxUnlock(&partition->lock);

    return 0;
}

int sbullCharClose(struct file *filep)
{
    return 0;
}

ssize_t sbullCharRead(struct file *filep, char *buffer, size_t buflen)
{
    return 0;
}

ssize_t sbullCharWrite(struct file *filep, const char *buffer, size_t buflen)
{
    return 0;
}

off_t sbullCharSeek(struct file *filep, off_t offset, int whence)
{
    return 0;
}

///////////////////////////////////////////////////////////////
// 块设备驱动
///////////////////////////////////////////////////////////////
int sbullBlkOpen(struct Vnode *vnode)
{
    return 0;
}

int sbullBlkClose(struct Vnode *vnode)
{
    return 0;
}

ssize_t sbullBlkRead(struct Vnode *vnode, unsigned char *buffer,
            unsigned long long start_sector, unsigned int nsectors)
{
    struct drv_data *data = NULL;
    mtd_partition *partition = NULL;
    struct MtdDev *mtd = NULL;

    uint32_t len;
    uint32_t start;

    uint8_t *p;
    int32_t size, ret;

    // drv_data
    data = vnode->data;
    if (data == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // partition
    partition = (mtd_partition *)data->priv;
	if (partition == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // mtd
    mtd = (struct MtdDev *)partition->mtd_info;
    if (mtd == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // 计算需要读取的字节数
    len = nsectors * mtd->eraseSize;
    start = start_sector * mtd->eraseSize;

    // copy from user
    if ((size = sbullPreRead((char *)buffer, len, (char **)&p)) != 0) {
        return size;
    }

    // mtd->read
    ret = mtd->read(mtd, start, len, (const char *)p);

    // copy to user
    return sbullPostRead((char *)buffer, (char *)p, len, ret);
}

ssize_t sbullBlkWrite(struct Vnode *vnode, const unsigned char *buffer,
            unsigned long long start_sector, unsigned int nsectors)
{
    struct drv_data *data = NULL;
    mtd_partition *partition = NULL;
    struct MtdDev *mtd = NULL;

    uint32_t len;
    uint32_t start;

    uint8_t *p;
    int32_t size, ret;

    // drv_data
    data = vnode->data;
    if (data == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // partition
    partition = (mtd_partition *)data->priv;
	if (partition == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // mtd
    mtd = (struct MtdDev *)partition->mtd_info;
    if (mtd == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // 计算要写入的字节数
    len = nsectors * mtd->eraseSize;
    start = start_sector * mtd->eraseSize;

    // copy from user
    if ((size = sbullPreWrite((char *)buffer, len, (char **)&p)) != 0) {
        return size;
    }

    // mtd->write
    ret = mtd->write(mtd, start, len, (char *)p);

    // copy to user
    return sbullPostWrite((char *)buffer, (char *)p, ret);
}

int sbullBlkGeometry(struct Vnode *vnode, struct geometry *geometry)
{
    struct drv_data *data = NULL;
    mtd_partition *partition = NULL;
    struct MtdDev *mtd = NULL;

    // drv_data
    data = vnode->data;
    if (data == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // partition
    partition = (mtd_partition *)data->priv;
	if (partition == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // mtd
    mtd = (struct MtdDev *)partition->mtd_info;
    if (mtd == NULL) {
		return HDF_ERR_INVALID_PARAM;
	}

    // 填充属性
    geometry->geo_available = TRUE,         // 使能
    geometry->geo_mediachanged = FALSE;     // 媒体未发生变化
    geometry->geo_writeenabled = TRUE;      // 可写
    geometry->geo_nsectors = mtd->size / mtd->eraseSize; // sectors = size / sectorsize
    geometry->geo_sectorsize = mtd->eraseSize; // sectorsize

    return 0;
}